package controllers

import (
	"chuanyouFive/models"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"
	"strconv"
	"strings"
	"time"

	beego "github.com/beego/beego/v2/server/web"
	"github.com/beego/beego/v2/server/web/context"
	"github.com/dgrijalva/jwt-go"
	"github.com/gorilla/websocket"
)

// 学生的接口
type ClassmatesController struct {
	beego.Controller
}

// URLMapping ...
func (c *ClassmatesController) URLMapping() {
	c.Mapping("Post", c.Post)
	c.Mapping("GetOne", c.GetOne)
	c.Mapping("GetAll", c.GetAll)
	c.Mapping("Put", c.Put)
	c.Mapping("Delete", c.Delete)
}

// Post ...
// @Title Post
// @Description 用户注册，用户添加
// @Param	body		body 	models.Classmates	true		"body for Classmates content"
// @Success 201 {int} models.Classmates
// @Failure 403 body is empty
// @router / [post]
func (c *ClassmatesController) Post() {
	var v models.Classmates
	var export models.Export
	if err := json.Unmarshal(c.Ctx.Input.RequestBody, &v); err == nil {
		if _, err := models.AddClassmates(&v); err == nil {
			c.Ctx.Output.SetStatus(201)
			export.Code = 0
			export.Data = v
			c.Data["json"] = export
		} else {
			export.Code = 1
			export.Data = err.Error()
			c.Data["json"] = export

		}
	} else {
		export.Code = 1
		export.Data = err.Error()
		c.Data["json"] = export
	}
	c.ServeJSON()
}

// GetOne ...
// @Title Get One
// @Description get Classmates by id
// @Param	id		path 	string	true		"The key for staticblock"
// @Success 200 {object} models.Classmates
// @Failure 403 :id is empty
// @router /:id [get]
func (c *ClassmatesController) GetOne() {
	idStr := c.Ctx.Input.Param(":id")
	id, _ := strconv.Atoi(idStr)
	v, err := models.GetClassmatesById(id)
	var export models.Export
	if err != nil {
		export.Code = 1
		export.Data = err.Error()
		c.Data["json"] = export
	} else {
		export.Code = 0
		export.Data = v
		c.Data["json"] = export
	}
	c.ServeJSON()
}

// GetAll ...
// @Title Get All
// @Description 用户查询
// @Param	query	query	string	false	"Filter. e.g. col1:v1,col2:v2 ..."
// @Param	fields	query	string	false	"Fields returned. e.g. col1,col2 ..."
// @Param	sortby	query	string	false	"Sorted-by fields. e.g. col1,col2 ..."
// @Param	order	query	string	false	"Order corresponding to each sortby field, if single value, apply to all sortby fields. e.g. desc,asc ..."
// @Param	limit	query	string	false	"Limit the size of result set. Must be an integer"
// @Param	offset	query	string	false	"Start position of result set. Must be an integer"
// @Success 200 {object} models.Classmates
// @Failure 403
// @router / [get]
func (c *ClassmatesController) GetAll() {
	var fields []string
	var sortby []string
	var order []string
	var query = make(map[string]string)
	var limit int64 = 10
	var offset int64

	// fields: col1,col2,entity.col3
	if v := c.GetString("fields"); v != "" {
		fields = strings.Split(v, ",")
	}
	// limit: 10 (default is 10)
	if v, err := c.GetInt64("limit"); err == nil {
		limit = v
	}
	// offset: 0 (default is 0)
	if v, err := c.GetInt64("offset"); err == nil {
		offset = v
	}
	// sortby: col1,col2
	if v := c.GetString("sortby"); v != "" {
		sortby = strings.Split(v, ",")
	}
	// order: desc,asc
	if v := c.GetString("order"); v != "" {
		order = strings.Split(v, ",")
	}
	var export models.Export
	// query: k:v,k:v
	if v := c.GetString("query"); v != "" {
		for _, cond := range strings.Split(v, ",") {
			kv := strings.SplitN(cond, ":", 2)
			if len(kv) != 2 {
				export.Code = 1
				export.Data = errors.New("Error: invalid query key/value pair")
				c.Data["json"] = export

				c.ServeJSON()
				return
			}
			k, v := kv[0], kv[1]
			query[k] = v
		}
	}

	l, err := models.GetAllClassmates(query, fields, sortby, order, offset, limit)
	if err != nil {
		export.Code = 1
		export.Data = err.Error()
		c.Data["json"] = export
	} else {
		export.Code = 0
		export.Data = l
		c.Data["json"] = export
	}
	c.ServeJSON()
}

// Put ...
// @Title Put
// @Description update the Classmates
// @Param	id		path 	string	true		"The id you want to update"
// @Param	body		body 	models.Classmates	true		"body for Classmates content"
// @Success 200 {object} models.Classmates
// @Failure 403 :id is not int
// @router /:id [put]
func (c *ClassmatesController) Put() {
	idStr := c.Ctx.Input.Param(":id")
	id, _ := strconv.Atoi(idStr)
	v := models.Classmates{Id: id}
	var export models.Export
	if err := json.Unmarshal(c.Ctx.Input.RequestBody, &v); err == nil {
		if err := models.UpdateClassmatesById(&v); err == nil {

			export.Code = 0
			export.Data = "OK"
			c.Data["json"] = export
		} else {
			export.Code = 1
			export.Data = err.Error()
			c.Data["json"] = export
		}
	} else {
		export.Code = 1
		export.Data = err.Error()
		c.Data["json"] = export
	}
	c.ServeJSON()
}

// Delete ...
// @Title 学生登录
// @Description 学生登录
// @Param	sn		query 	string	true		" 学生学号"
// @Param	pswd		query 	string	true		" 学生密码"
// @Success 200 {string} delete success!
// @Failure 403 id is empty
// @router /login [get]
func (c *ClassmatesController) Login() {
	// 1. 接收参数
	var sn = c.GetString("sn")
	var pswd = c.GetString("pswd")

	var export models.Export
	//2 .业务处理
	user := models.Login(sn, pswd)
	if user == nil {
		export.Code = 1
		export.Data = "登录失败"
		c.Data["json"] = export
		c.ServeJSON()
		return
	}
	// 3.输出
	export.Code = 0
	export.Data = user
	// 都有 第三方工具帮你做了。
	// 1、  登录成功后  制造令牌  。  用  models.GetJwtString(2, user.Id, 2)  制造
	export.Title, _ = models.GetJwtString(2, user.Name, user.Sn, user.Id, 2)
	c.Data["json"] = export
	c.ServeJSON()
}

// Delete ...
// @Title 学生登录
// @Description 转账
// @Param	xuexiao		path 	string	true		" 学校"
// @Param	xueyuan		path 	string	true		" 学院"
// @Param	zhuanye		path 	string	true		" 专业"
// @Param	sn		path 	string	true		" 学号"
// @Success 200 {string} delete success!
// @Failure 403 id is empty
// @router /:xuexiao/:xueyuan/:zhuanye/:sn [get]
func (c *ClassmatesController) Ceshi() {
	// 1. 接收参数
	// 我的规矩就是规矩

}

// Delete ...
// @Title 修改资料
// @Description 修改资料
// @Param	id		path 	string	true		"学号"
// @Param	body		body 	models.Classmates	true		"学生新资料"
// @Success 200 {string} delete success!
// @Failure 403 id is empty
// @router /modifyInfo/:id [post]
func (c *ClassmatesController) ModifyInfo() {
	// 1. 接收参数
	idStr := c.Ctx.Input.Param(":id")
	id, _ := strconv.Atoi(idStr)
	var v models.Classmates
	var export models.Export
	if err := json.Unmarshal(c.Ctx.Input.RequestBody, &v); err != nil {
		export.Code = 1
		export.Data = "登录失败" + err.Error()
		c.Data["json"] = export
		c.ServeJSON()
		return
	}
	// 2.调用models的逻辑函数处理
	result := models.ModifyInfo(id, &v)
	if result == false {
		export.Code = 1
		export.Data = "修改用户资料失败"
		c.Data["json"] = export
		c.ServeJSON()
		return
	}
	// 3.输出结果
	export.Code = 0
	export.Data = "修改用户资料成功"
	c.Data["json"] = export
	c.ServeJSON()
}

// Delete ...
// @Title 修改密码
// @Description 修改密码
// @Param	oldpswd		query 	string	true		"旧密码"
// @Param	newpswd		query 	string	true		"新密码"
// @Success 200 {string} delete success!
// @Failure 403 id is empty
// @router /modifyPswd/:id [get]
func (c *ClassmatesController) ModifyPswdLu9olashi() {
	// 1. 接收参数

	id64, _ := c.Ctx.Input.GetData("userid").(float64)
	id := int(id64)
	oldpswd := c.GetString("oldpswd")
	newpswd := c.GetString("newpswd")
	var export models.Export
	// 2.调用逻辑
	result := models.ModifyPsed(id, oldpswd, newpswd)
	if result == false {
		export.Code = 1
		export.Data = "修改密码失败"
		c.Data["json"] = export
		c.ServeJSON()
		return
	}

	// 3.输出结果
	export.Code = 0
	export.Data = "修改密码成功"
	c.Data["json"] = export
	c.ServeJSON()
}

// Delete ...
// @Title 学生转账
// @Description 转账
// @Param	senderid		path 	string	true		"发送方的id"
// @Param	receiveid		path 	string	true		"接收方的id"
// @Param	edu		query 	float64	true		"转账的额度"
// @Success 200 {string} delete success!
// @Failure 403 id is empty
// @router /zhuanzhang/:senderid/:receiveid [get]
func (c *ClassmatesController) Zhuanzhang() {
	// 1. 接收参数
	senderidStr := c.Ctx.Input.Param(":senderid")
	senderid, _ := strconv.Atoi(senderidStr)

	receiveidStr := c.Ctx.Input.Param(":receiveid")
	receiveid, _ := strconv.Atoi(receiveidStr)

	edu, _ := c.GetFloat("edu")
	var export models.Export
	// 2。调用逻辑
	yuanyin, shijian, result := models.Zhuanzhang(senderid, receiveid, edu)
	if result == false {
		export.Code = 1
		export.Data = shijian.Format("2006/01/02  15:04分05秒") + yuanyin
		c.Data["json"] = export

		c.ServeJSON()
		return
	}

	// 3.输出
	export.Code = 0
	export.Data = shijian.Format("2006年01/02 15:04分05秒") + "转账成功"
	c.Data["json"] = export
	c.ServeJSON()
}

// 用户令牌验证
func FilterUser(ctx *context.Context) {
	if strings.Contains(ctx.Input.URL(), "/login") {
		// 用户登录 不需要令牌验证
		return
	}
	if strings.Contains(ctx.Input.URL(), "/getChouJiangRenList") {
		// 抽奖 不需要令牌验证
		return
	}
	if strings.Contains(ctx.Input.URL(), "/static/") {
		// 抽奖 不需要令牌验证
		return
	}

	authString := ctx.Input.Header("Authorization")
	fmt.Println("收到的令牌是:", authString)
	token := new(jwt.Token)
	token.Valid = false
	var err error
	if authString != "" {
		token, err = jwt.Parse(authString, func(token *jwt.Token) (interface{}, error) {
			return []byte(models.JwtMiyao), nil
		})
		if err != nil {
			ctx.Output.JSON("解密失败", false, false)
			return
		}
	} else {
		ctx.Output.JSON("没有令牌", false, false)
		return
	}
	if token.Valid {
		userinfo, ok := token.Claims.(jwt.MapClaims)
		if ok == false {
			ctx.Output.JSON("用户信息异常", false, false)
			return
		}
		if userinfo["id"] == nil || userinfo["id"] == "" {
			return
		}
		expireTime := userinfo["exp"].(float64)
		if int(expireTime) <= int(time.Now().Unix()) {
			ctx.Output.JSON("登陆已经过期", false, false)
			return
		}
		// 5. 把合法令牌中的  id 取出来， 给后续的接口使用。
		fmt.Println("userinfo:", userinfo)
		ctx.Input.SetData("userid", userinfo["id"])

	}
}

// 定义WebSocket连接的升级器
var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	// 允许跨域请求（这里只是示例，实际应用中需根据情况谨慎设置）
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

var allUserConn []*websocket.Conn

// Delete ...
// @Title websocket  接口
// @Description 实时获取动态数据
// @Success 200 {string} delete success!
// @Failure 403 id is empty
// @router /getChouJiangRenList [get]
func (c *ClassmatesController) GetChouJiangRenList() {
	// 1. 接收参数
	// websocket 全双工   的通信技术
	conn, err := upgrader.Upgrade(c.Ctx.ResponseWriter, c.Ctx.Request, nil)
	if err != nil {
		log.Println(err)
		return
	}
	defer conn.Close()
	allUserConn = append(allUserConn, conn)
	for {
		//1. 从webscoekt连接中 读取用户的消息
		_, msg, _ := conn.ReadMessage()
		// ----------------------
		// 2.调用阿里云的ai  进行回答，获取 答案，存入answer变量
		anwser := models.CallAliyunAi(string(msg))
		// 3.将 answer 再发回给前端用户。
		conn.WriteMessage(1, []byte(anwser))
	}
}

// UploadFace ...
// @Title 上传头像
// @Description 上传头像
// @Param	uploadname		query 	file	true		"上传的文件"
// @Success 200 {string} upload success!
// @Failure 403 id is empty
// @router /upload/face [post]
func (c *ClassmatesController) UploadFace() {
	var export models.Export
	f, h, err := c.GetFile("uploadname")
	if err != nil {
		export.Code = 1001
		export.Title = "上传失败"
		export.Data = err
		c.Data["json"] = export
		c.ServeJSON()
		return
	}
	defer f.Close()

	nameList := strings.Split(h.Filename, ".")
	extName := nameList[len(nameList)-1]
	var newFileName string = time.Now().Format("20060102150405") + "." + extName

	c.SaveToFile("uploadname", "static/upload/"+newFileName) // 保存位置在 static/upload, 没有文件夹要先创建
	// 将用户的头像地址  保存到他自己的face字段里
	userid := c.Ctx.Input.GetData("userid").(float64)
	if models.SetUserFace(fmt.Sprintf("%v", userid), "static/upload/"+newFileName) == false {
		export.Code = 1001
		export.Title = "上传失败"
		export.Data = " 修改头像失败"
		c.Data["json"] = export
		c.ServeJSON()
		return
	}

	export.Code = 1000
	export.Title = "上传成功"
	export.Data = "static/upload/" + newFileName
	c.Data["json"] = export
	c.ServeJSON()
}

// GaoBingFa ...
// @Title 高并发演示
// @Description 高并发演示
// @Success 200 {string} upload success!
// @Failure 403 id is empty
// @router /gaoBingFa [get]
func (c *ClassmatesController) GaoBingFa() {
	var export models.Export
	// 定义一个 存储int的通道，通道长度为10
	var tongdao = make(chan int, 10)

	// 启动 100个协程，往通道写进去
	var zongShuju = 500000000
	// --------------单协程
	var starttime = time.Now()
	var result int
	for i := 0; i < zongShuju; i++ {
		result = result + i
	}
	fmt.Println("单个协程累计的结果是:", result, " 花掉时间:", time.Now().Sub(starttime).String())

	// ----------  多线程，100个协程
	var danShuju = zongShuju / 50
	starttime = time.Now()
	result = 0
	for i := 0; i < 50; i++ {
		go models.QiuHe(tongdao, i*danShuju, (i+1)*danShuju)
	}

	// 用一个协程 读出来

	for i := 0; i < 50; i++ {
		item := <-tongdao
		result = result + item
	}

	fmt.Println("多个协程累计的结果是:", result, " 花掉时间:", time.Now().Sub(starttime))

	c.Data["json"] = export
	c.ServeJSON()
}
